#include "Cam.h"

/**
 * @brief 构造函数，判断cfg文件是否为空
 * @param const std::string names 用于yolo识别的类型名
 * @param const std::string cfg 参数配置文件路劲
 * @param const std::string weight yolo的权值文件
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com
 */
Cam::Cam(const std::string names, const std::string cfg, const std::string weight) : Detector(cfg, weight)
{
    if (names.empty() || cfg.empty() || weight.empty())
    {
        std::cerr << "The yolo directory should not be empty!" << std::endl;
        exit(-1);
    }
}

/**
 * @brief 相机抓图函数，获取图像数据。此函数是创建相机抓图线程，在循环内不断抓取图片。
 * @param void
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com
 */
void Cam::grab()
{
    //用cv载入yml文件对参数进行读入
    cv::FileStorage LoadMycfg("../YmlFiles/Dahua.yml", cv::FileStorage::READ);
    LoadMycfg["Width"] >> m_width;
    LoadMycfg["Height"] >> m_height;
    LoadMycfg["R"] >> m_r;
    LoadMycfg["G"] >> m_g;
    LoadMycfg["B"] >> m_b;
    m_balance = {m_r / 100.0, m_g / 100.0, m_b / 100.0};
    LoadMycfg["Brightness"] >> m_brightness;
    LoadMycfg["BlackLevel"] >> m_blacklevel;
    LoadMycfg["DigitalShift"] >> m_digitalshift;
    LoadMycfg["Gainraw"] >> m_gainraw;
    LoadMycfg["Gama"] >> m_gama;
    LoadMycfg["EXPOSURE"] >> m_exposure;
    LoadMycfg["Sharpness"] >> m_sharpness;
    LoadMycfg.release(); //完成读入，释放文件

    Lagori_ = cv::Mat::zeros(m_height, m_width, CV_8UC3);
    double stime, etime;
    std::string result;

    //打开大华相机
    hitcrt::MyDahuaCam DahuaCam("auto", m_width, m_height, m_exposure, m_brightness, m_digitalshift, m_balance, m_blacklevel, m_gama / 100.0, 1, m_sharpness);
    std::shared_ptr<cv::Mat> frame;
    struct timeval timer;
    gettimeofday(&timer, NULL);
    stime = timer.tv_sec * 1e3 + timer.tv_usec * 1e-3;
    double fps;
    cv::namedWindow("frame", cv::WINDOW_FREERATIO);
    while (true) //抓图死循环
    {
        DahuaCam.grab();
        frame = DahuaCam.getImage();
        if (frame != nullptr && !frame->empty())
        {
            Lag_Mut.lock();
            Lagori_ = frame->clone();
            Lag_Mut.unlock();
            gettimeofday(&timer, NULL);
            etime = timer.tv_sec * 1e3 + timer.tv_usec * 1e-3;
            fps = 1000 / (etime - stime);
            stime = etime;
            // std::cout << "FPS: " << fps << std::endl;
            cv::imshow("frame", *frame);
            cv::waitKey(1);
        }
    }
}


/**
 * @brief 外部获取图像函数
 * @param void
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com
 */
void Cam::getImg(void)
{
    Lag_Mut.lock();
    m_originImg = Lagori_.clone();
    Lag_Mut.unlock();
}


/**
 * @brief 调用Yolo对图像中的Lagori进行识别
 * @param cv::Mat& 
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com
 */
void Cam::detectLag(const cv::Mat& inputImg)
{
    Lag_Mut.lock();
    Lag_Boxs = Cam::detect(inputImg); //调用yolo的识别函数
    std::cout << "the num of Lagori is: " << Lag_Boxs.size() << std::endl;

    // std::vector<std::vector<cv::Point>> tPoints;
    // 获取每个Lagori框的位置与类别
    for (auto& i : Lag_Boxs)
    {
        std::vector<cv::Point> Point2;
        Point2.push_back(cv::Point(i.x, i.y));
        Point2.push_back(cv::Point(i.x + i.w, i.y + i.h));
        Lpoints_.push_back(Point2);
        tags_.push_back(i.obj_id);
    }
    Lag_Mut.unlock();
    // LPoints.swap(tPoints);
    if (tags_.size() != 0)
    {
        std::cout << "获取Lagori成功！ " << std::endl;
        return;
    }

    std::cout << "获取Lagori失败！ " << std::endl;
    return;
}

/**
 * @brief 获取识别出的Lagori框
 * @param std::vector<std::vector<cv::Point>>& 
 * @param std::vector<int>&
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com 
 */
void Cam::getLag(std::vector<std::vector<cv::Point>>& Lpoints, std::vector<int>& tags)
{
    Lag_Mut.lock();
    Lpoints = Lpoints_;
    tags = tags_;
    Lag_Mut.unlock();
}


/**
 * @brief 获取相机的原始图像
 * @param cv::Mat& 
 * @return bool 
 * @author Milo
 *  -QQ:2601171627; Email:milo_name@outlook.com
 */
bool Cam::getOriginImg(cv::Mat& outputImg)
{
    Lag_Mut.lock();
    outputImg = m_originImg.clone();
    Lag_Mut.unlock();
    if (!outputImg.empty())
    {
        return true;
    }
    return false;
}